/*********************************************************************************
 *      Copyright:  (C) 2025 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  sampling.c
 *    Description:  This file is sampling modulule
 *                 
 *        Version:  1.0.0(06/04/25)
 *         Author:  huangzixiao<2027838269@qq.com>
 *      ChangeLog:  1, Release initial version on "06/04/25 15:19:43"
 *                 
 ********************************************************************************/

#include "ds18b20.h"
#include "packet.h"
#include "logger.h"

#define DEVICE_MIN_LEN          8
#define TIME_LEN   			32
#define TLV_MINSIZE         7
#define TLV_HEADER          0xFEED

int get_time(struct tm *ptm);
int get_device(char *device, int d_size, int sn);

int sampling(pack_data_t *data)
{

	int						rv;
	char					*device = NULL;
	int						sn = 11;


	//get temperature
	rv  = ds18b20_get_tempareture(&data->temperature);
	if(rv < 0)
	{
		log_error("get temperature failure\n");
		goto out;
	}

	//get device
	rv = get_device(data->device, sizeof(data->device), sn);
	if( rv < 0)
	{
		log_error("get device failure\n");
		goto out;
	}

	//get time
	rv =  get_time(&data->time);
	if(rv < 0)
	{
		log_error("get time failure\n");
		goto out;
	}

	return 0;

out:
	return -1;
}



int get_device(char *device, int d_size, int sn)
{

	if(!device || d_size<DEVICE_MIN_LEN )//the length of min device serial number is 8 bytes
	{
		log_error("invalid argument\n");
		return -1;
	}

	memset(device, 0, d_size);
    snprintf(device, d_size, "rpi#%04d", sn);
    return 0;
}



int get_time(struct tm *ptm)
{
    if( !ptm )
    {   
        log_error("Invalid input arugments\n");
        return -1; 
    }   
 
    time_t now = time(NULL);
    localtime_r(&now, ptm);
 
    return 0;
}

int packet_segmented_pack(pack_data_t *pack_data, uint8_t *pack_buf, int size)
{
	char              strtime[TIME_LEN] = {'\0'};
	struct tm        *ptm;
	char             *buf = (char *)pack_buf;

	if( !pack_data || !buf || size<=0 )
	{
		log_error("Invalid input arguments\n");
		return -1;
	}

	ptm = &pack_data->time;
	snprintf(strtime, sizeof(strtime), "%04d-%02d-%02d %02d:%02d:%02d",
			ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
			ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

	memset(buf, 0, size);
	snprintf(buf, size, "%s|%s|%.3f", pack_data->device, strtime, pack_data->temperature);

	return strlen(buf);
}
/* struct tm {
    int tm_sec;    // 秒 [0-60]（允许闰秒）
    int tm_min;    // 分 [0-59]
    int tm_hour;   // 时 [0-23]
    int tm_mday;   // 日 [1-31]
    int tm_mon;    // 月 [0-11]（0=一月）
    int tm_year;   // 年（从1900年起的偏移量）
    int tm_wday;   // 星期 [0-6]（0=星期日）
    int tm_yday;   // 一年中的第几天 [0-365]
    int tm_isdst;  // 夏令时标志：
                   // 正数=夏令时，0=非夏令时，负数=未知
}; */


int packet_json_pack(pack_data_t *pack_data, uint8_t *pack_buf, int size)
{
	char              strtime[TIME_LEN] = {'\0'};
	struct tm        *ptm;
	char             *buf = (char *)pack_buf;

	if( !pack_data || !buf || size<=0 )
	{
		log_error("Invalid input arguments\n");
		return -1;
	}

	ptm = &pack_data->time;
	snprintf(strtime, sizeof(strtime), "%04d-%02d-%02d %02d:%02d:%02d",
			ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
			ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

	memset(buf, 0, size);
	snprintf(buf, size, "{\"device\":\"%s\", \"time\":\"%s\", \"temperature\":\"%.3f\"}",
			pack_data->device, strtime, pack_data->temperature);

	return strlen(buf);

}

uint16_t to_big_endian(uint16_t num)
{
	return (num << 8) | (num >> 8);
}
#define TAG_TEMPERATURE 1

int packet_tlv_pack(pack_data_t *pack_data, uint8_t *pack_buf, int size)
{
	int					i;
	int					j;
	struct tm          *ptm;
    int                 ofset = 0;//?
    uint16_t            crc;//校验码
    uint16_t            header = TLV_HEADER;

    if( !pack_data || !pack_buf || size<TLV_MINSIZE )

    {
        log_error("Invalid input arguments\n");
        return -1;
    }

	/* tlv Header 2B */
	*(uint16_t *)pack_buf = to_big_endian(TLV_HEADER);
	//log_debug("Header:0x%X%X\n", pack_buf[0], pack_buf[1]);
	
	/* tlv tag 1B*/
	ofset += 2;
	pack_buf[ofset++] = TAG_TEMPERATURE;
	//log_debug("Tag:%d\n", pack_buf[2]);

	/* tlv value length 2B */
	ofset += 2;

	/* tlv value nB*/
	/* device */
    strncpy((char *)(pack_buf+ofset), pack_data->device, strlen(pack_data->device));
    ofset += strlen(pack_data->device);

	/*log_debug("device:\n");
	for(i; i<ofset; i++)
	{
		log_debug("%c\n", (char *)pack_buf[i]);
	}
	*/

	/* time */
    ptm = &pack_data->time;
    pack_buf[ofset++] = (uint8_t)(ptm->tm_year+1900-2000);
    pack_buf[ofset++] = (uint8_t)(ptm->tm_mon+1);
    pack_buf[ofset++] = (uint8_t)(ptm->tm_mday);
    pack_buf[ofset++] = (uint8_t)(ptm->tm_hour);
    pack_buf[ofset++] = (uint8_t)(ptm->tm_min);
    pack_buf[ofset++] = (uint8_t)(ptm->tm_sec);

	/* temperature */
    pack_buf[ofset++] = (int)pack_data->temperature;  /* integer part */
    pack_buf[ofset++] = (((int)(pack_data->temperature*100))%100); /* fractional part */


	/* ensure length value*/
    *(uint16_t *)(pack_buf + 3) = to_big_endian((uint16_t)(ofset - 5));//减去前面5B
											  //|Header	|Tag|length	|			value		|
                                              //|2B		|1B	|2B		|						|
											  //|		5B			|						|

	/* tlv CRC 2B*/
	crc = crc_itu_t(pack_buf, ofset);
    *(uint16_t *)(pack_buf+ofset) = crc;
    ofset += 2;

	return ofset;//tlv length
}

/* CRC校验码 */
#define CRC16_ITU_T_POLY 0x1021   /* Define the CRC-ITU-T polynomial */
static uint16_t crc_itu_t(const uint8_t *data, size_t length)
{
    uint16_t          crc = 0xFFFF;
    size_t            i, j;

    for (i=0; i<length; i++)
    {
        crc ^= ((uint16_t)data[i] << 8);

        for(j=0; j<8; j++)
        {
            if (crc & 0x8000)
            {
                crc = (crc << 1) ^ CRC16_ITU_T_POLY;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}

